---
title: Automatic Persisted Queries (APQ)
subtitle: Configure caching for automatic persisted queries
description: Configure automatic persisted queries (APQ) in GraphOS Router to reduce network usage by sending query hashes instead of full query strings.
---

[Automatic Persisted Queries (**APQ**)](/apollo-server/performance/apq) enable GraphQL clients to send a server the _hash_ of their query string, _instead of_ sending the query string itself. When query strings are very large, this can significantly reduce network usage.

The router supports using APQ in its communications with both clients _and_ subgraphs:

- **In its communications with clients,** the router acts as a GraphQL _server_, because it _receives_ queries from clients.
- **In its communications with subgraphs,** the router acts as a GraphQL _client_, because it _sends_ queries to subgraphs.

Because the router's role differs between these two interactions, you configure these APQ settings separately.

## In-memory caching

The router uses an in-memory LRU cache to store automatic persisted queries. You can configure certain caching behaviors for APQ.

### APQ with clients

The router enables APQ caching for client operations by default. In your router's [YAML config file](/graphos/routing/configuration/overview#yaml-config-file), you can configure the maximum number of APQ entries in the cache like so:

```yaml title="router.yaml"
apq:
  router:
    cache:
      in_memory:
        limit: 512 # This is the default value.
```

You can also _disable_ client APQ support entirely like so:

```yaml title="router.yaml"
apq:
  enabled: false
```

### APQ with subgraphs

By default, the router does _not_ use APQ when sending queries to its subgraphs.

In your router's [YAML config file](/graphos/routing/configuration/overview#yaml-config-file), you can configure this APQ support with a combination of global and per-subgraph settings:

```yaml title="router.yaml"
apq:
  subgraph:
    # Disables subgraph APQ globally except where overridden per-subgraph
    all:
      enabled: false
    # Override global APQ setting for individual subgraphs
    subgraphs:
      products:
        enabled: true
```

In the example above, subgraph APQ is disabled _except for_ the `products` subgraph.

<Note>

To use APQ with subgraphs effectively, your subgraph server should have a shared cache that can store all incoming operations. If the cache is too small or isn't shared between multiple instances of the subgraph server, the router sends extra requests on cache misses to resolve the operation. Consult your subgraph server framework's documentation to ensure it supports APQ and to configure caching options.

</Note>

## Distributed caching with Redis

<PlanRequired plans={["Free", "Developer", "Standard", "Enterprise"]}>

Rate limits apply on the Free plan.
Performance pricing applies on Developer and Standard plans.
Developer and Standard plans require Router v2.6.0 or later.

</PlanRequired>

If you have multiple GraphOS Router instances, those instances can share a Redis-backed cache for their automatic persisted queries (APQ). This means that if _any_ of your router instances caches a particular APQ query string, _all_ of your instances can look up that value to significantly improve responsiveness.

### Prerequisites

To use distributed caching:

- You must have a Redis cluster (or single instance) that your router instances can communicate with.
- You must have a [GraphOS Enterprise plan](https://www.apollographql.com/pricing/) and [connect your router to GraphOS](/graphos/routing/configuration/overview#environment-variables).

### How it works

Whenever a router instance requires an APQ query string to resolve a client operation:

1. The router instance checks its own [in-memory cache](#in-memory-caching) for the required value and uses it if found.
2. If _not_ found, the router instance then checks the distributed Redis cache for the required value and uses it if found. It also then replicates the found value in its own in-memory cache.
3. If _not_ found, the router instance requests the full operation string from the client for APQ.
4. The router instance stores the obtained value in both the distributed cache _and_ its in-memory cache.

### Redis URL configuration

The distributed caching configuration must contain one or more URLs using different schemes depending on the expected deployment:

- `redis` — TCP connected to a centralized server.
- `rediss` — TLS connected to a centralized server.
- `redis-cluster` — TCP connected to a cluster.
- `rediss-cluster` — TLS connected to a cluster.
- `redis-sentinel` — TCP connected to a centralized server behind a sentinel layer.
- `rediss-sentinel` — TLS connected to a centralized server behind a sentinel layer.

The URLs must have the following format:

#### One node

```
redis|rediss :// [[username:]password@] host [:port][/database]
```

Example: `redis://localhost:6379`

#### Clustered

```
redis|rediss[-cluster] :// [[username:]password@] host [:port][?[node=host1:port1][&node=host2:port2][&node=hostN:portN]]
```

or, if configured with multiple URLs:

```
[
  "redis|rediss[-cluster] :// [[username:]password@] host [:port]",
  "redis|rediss[-cluster] :// [[username:]password@] host1 [:port1]",
  "redis|rediss[-cluster] :// [[username:]password@] host2 [:port2]"
]
```

#### Sentinel

```
redis|rediss[-sentinel] :// [[username1:]password1@] host [:port][/database][?[node=host1:port1][&node=host2:port2][&node=hostN:portN]
                            [&sentinelServiceName=myservice][&sentinelUsername=username2][&sentinelPassword=password2]]
```

or, if configured with multiple URLs:

```
[
  "redis|rediss[-sentinel] :// [[username:]password@] host [:port][/database][?[&sentinelServiceName=myservice][&sentinelUsername=username2][&sentinelPassword=password2]]",
  "redis|rediss[-sentinel] :// [[username1:]password1@] host [:port][/database][?[&sentinelServiceName=myservice][&sentinelUsername=username2][&sentinelPassword=password2]]"
]
```

### Router configuration

<Tip>

In your router's YAML config file, **you should specify your Redis URLs via environment variables and [variable expansion](/graphos/routing/configuration/overview#variable-expansion)**. This prevents your Redis URLs from being committed to version control, which is especially dangerous if they include authentication information like a username and/or password.

</Tip>

To enable distributed caching of automatic persisted queries (APQ), add the following to your router's [YAML config file](/graphos/routing/configuration/overview#yaml-config-file):

```yaml title="router.yaml"
apq:
  router:
    cache:
      redis:
        urls: ["redis://..."]
```

The value of `urls` is a list of URLs for all Redis instances in your cluster.

All APQ cache entries will be prefixed with `apq` followed by a null byte character (referenced by the escape sequence `\0` in most programming languages) within the distributed cache.

### Redis configuration options

```yaml title="router.yaml"
apq:
  router:
    cache:
      redis:
        urls: ["redis://..."]
        username: admin/123 # Optional, can be part of the urls directly, mainly useful if you have special character like '/' in your password that doesn't work in url. This field takes precedence over the username in the URL
        password: admin # Optional, can be part of the urls directly, mainly useful if you have special character like '/' in your password that doesn't work in url. This field takes precedence over the password in the URL
        timeout: 2s # Optional, by default: 500ms
        ttl: 24h # Optional, default is no expiration
        namespace: "prefix" # Optional
        #tls:
        required_to_start: false # Optional, defaults to false
        reset_ttl: true # Optional, defaults to true
        pool_size: 4 # Optional, defaults to 1
```

#### Timeout

Connecting and sending commands to Redis are subject to a timeout, set by default to 500ms, that can be overridden.

#### TTL

The `ttl` option defines the default global expiration for Redis entries. For APQ caching, the default is no expiration.

#### Namespace

When using the same Redis instance for multiple purposes, the `namespace` option defines a prefix for all the keys defined by the router.

#### TLS

For Redis TLS connections, you can set up a client certificate or override the root certificate authority by configuring `tls` in your router's [YAML config file](/graphos/routing/configuration/overview#yaml-config-file). For example:

```yaml
apq:
  router:
    cache:
      redis:
        urls: ["rediss://redis.example.com:6379"]
        tls:
          certificate_authorities: ${file./path/to/ca.crt}
          client_authentication:
            certificate_chain: ${file./path/to/certificate_chain.pem}
            key: ${file./path/to/key.pem}
```

#### Required to start

When active, the `required_to_start` option will prevent the router from starting if it cannot connect to Redis. By default, the router will still start without a connection to Redis, which would result in only using the in-memory cache for APQ.

#### Reset TTL

When this option is active, accessing a cache entry in Redis will reset its expiration.

#### Pool size

The `pool_size` option defines the number of connections to Redis that the router will open. By default, the router will open a single connection to Redis. If there is a lot of traffic between router and Redis and/or there is some latency in those requests, it is recommended to increase the pool size to reduce that latency.
